\defmodule {Resource}

Objects of this class are resources having limited capacity,
and which can be requested and released by \class{Process} objects.
These resources act indirectly as synchonization devices for
processes.

A resource is created with a finite capacity, specified when 
invoking the \method{Resource}{int} constructor, and can be changed
later on.  A resource also has an infinite-capacity queue
(waiting line) and a service policy that defaults to FIFO and
can be changed later on.

A process must ask for a certain number of units of the resource
(\method{request}{}), and obtain it before using it.
When it is done with the resource, the process must release 
it so that others can use it (\method{release}{}).
A process does not have to request [release] all the resource
units that it needs by a single call to the \method{request}{}
[\method{release}{}] method.  It can make several successive requests
or releases, and can also hold different resources simultaneously.

Each resource maintains two lists: one contains the processes 
waiting for the resource (the waiting queue) and the other contains
the processes currently holding units of this resource.
The methods \method{waitList}{} and \method{servList}{} permit one to
access these two lists.
These lists actually contain objects of the class \class{UserRecord}
instead of \class{SimProcess} objects.

\bigskip\hrule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{code}
\begin{hide}
/*
 * Class:        Resource
 * Description:  resources with limited capacity which can be requested 
                 and released by Process objects.
 * Environment:  Java
 * Software:     SSJ 
 * Copyright (C) 2001  Pierre L'Ecuyer and Universite de Montreal
 * Organization: DIRO, Universite de Montreal
 * @author       
 * @since

 * SSJ is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License (GPL) as published by the
 * Free Software Foundation, either version 3 of the License, or
 * any later version.

 * SSJ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * A copy of the GNU General Public License is available at
   <a href="http://www.gnu.org/licenses">GPL licence site</a>.
 */
\end{hide}
package umontreal.iro.lecuyer.simprocs;
\begin{hide}
import java.util.ListIterator;
import umontreal.iro.lecuyer.util.PrintfFormat;
// import umontreal.iro.lecuyer.simevents.Simulator;
import umontreal.iro.lecuyer.simevents.LinkedListStat;
import umontreal.iro.lecuyer.simevents.Accumulate;
import umontreal.iro.lecuyer.simprocs.ProcessSimulator;
import umontreal.iro.lecuyer.stat.Tally;
\end{hide}

public class Resource \begin{hide} {

   private static final int FIFO  = 1;
   private static final int LIFO  = 2;

        private ProcessSimulator sim;

        private String name;
        private int capacity = 0;
        private int available = 0;
        private int policy = FIFO;

        private LinkedListStat<UserRecord> serviceList;
        private LinkedListStat<UserRecord> waitingList;

        private boolean    stats = false;
        private double     initStatTime;
        private Accumulate statUtil;
        private Accumulate statCapacity;
        private Tally      statSojourn;
\end{hide}\end{code}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection* {Constructors}
\begin{code}

   public Resource (int capacity) \begin{hide} {
      this (capacity, "");
   }\end{hide}
\end{code}
\begin{tabb}  Constructs a new resource linked with the default simulator,
  with initial capacity \texttt{capacity}, and service policy FIFO.
\end{tabb}
\begin{htmlonly}
   \param{capacity}{initial capacity of the resource}
\end{htmlonly}
\begin{code}

   public Resource (ProcessSimulator sim, int capacity) \begin{hide} {
      this (sim, capacity, "");
   }\end{hide}
\end{code}
\begin{tabb}  Constructs a new resource linked with the simulator
 \texttt{sim}, with initial capacity \texttt{capacity}, and service policy FIFO.
\end{tabb}
\begin{htmlonly}
   \param{sim}{current simulator of the variable}
   \param{capacity}{initial capacity of the resource}
\end{htmlonly}
\begin{code}

   public Resource (int capacity, String name) \begin{hide} {
      try {
         ProcessSimulator.initDefault();
         this.sim = (ProcessSimulator)ProcessSimulator.getDefaultSimulator();
         this.capacity = available = capacity;
         this.name = name;
         serviceList = new LinkedListStat<UserRecord> (
              sim," Service List for " + name);
         waitingList = new LinkedListStat<UserRecord> (
              sim," Waiting List for " + name);
      }
      catch (ClassCastException e) {
         throw new IllegalArgumentException("Wrong default Simulator type");
      }
   }\end{hide}
\end{code}
\begin{tabb} Constructs a new resource linked with the default simulator, with
 initial capacity \texttt{capacity}, service policy FIFO, and identifier 
 \texttt{name}.
\end{tabb}
\begin{htmlonly}
   \param{capacity}{initial capacity of the resource}
   \param{name}{identifier or name of the resource}
\end{htmlonly}
\begin{code}

   public Resource (ProcessSimulator sim, int capacity, String name) \begin{hide} {
      this.capacity = available = capacity;
      this.name = name;
      this.sim = sim;
      serviceList = new LinkedListStat<UserRecord> (
          sim," Service List for " + name);
      waitingList = new LinkedListStat<UserRecord> (
          sim," Waiting List for " + name);
   }\end{hide}
\end{code}
\begin{tabb}  Constructs a new resource linked with the simulator \texttt{sim},
   with initial capacity \texttt{capacity},
   service policy FIFO, and identifier (or name) \texttt{name}.
\end{tabb}
\begin{htmlonly}
   \param{sim}{current simulator of the variable}
   \param{capacity}{initial capacity of the resource}
   \param{name}{identifier or name of the resource}
\end{htmlonly}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection* {Methods}
\begin{code}

   public void setStatCollecting (boolean b) \begin{hide} {
      if (b) {
         if (stats)
            throw new IllegalStateException ("Already collecting statistics for this resource");
         stats = true;
         waitingList.setStatCollecting (true);
         serviceList.setStatCollecting (true);
         
         if (statUtil != null)
            initStat();
         else {
            statUtil = new Accumulate (sim, "StatOnUtil");
            statUtil.update (capacity - available);
            statCapacity = new Accumulate (sim, "StatOnCapacity");
            statCapacity.update (capacity);
            statSojourn = new Tally ("StatOnSojourn");
         }
      }
      else {
         if (stats)
           throw new IllegalStateException ("Not collecting statistics for this resource");
         stats = false;
         waitingList.setStatCollecting (false);
         serviceList.setStatCollecting (false);
      }
   }\end{hide}
\end{code}
\begin{tabb}  Starts or stops collecting statistics on the lists returned
  by \method{waitList}{} and \method{servList}{} for this resource.
  If the statistical collection is turned ON, the method
  also constructs (if not yet done) 
  and initializes three additional statistical
  collectors for this resource.  These collectors will be updated
  automatically.  They can be accessed via \method{statOnCapacity}{},
  \method{statOnUtil}{}, and \method{statOnSojourn}{}, respectively.
  The first two, of class
   \externalclass{umontreal.iro.lecuyer.simevents}{Accumulate},
   monitor the evolution of the
  capacity and of the utilization (number of units busy) of the resource 
  as a function of time.
  The third one, of class \externalclass{umontreal.iro.lecuyer.stat}{Tally},
  collects statistics on the 
  processes sojourn times (wait + service);  it samples a new value
  each time a process releases all the units of this resource that it
  holds (i.e., when its \class{UserRecord} disappears).
\end{tabb}
\begin{htmlonly}
   \param{b}{\texttt{true} to turn statistical collecting ON, \texttt{false} to turn it OFF}
\end{htmlonly}
\begin{code}

   public void initStat() \begin{hide} {
        if (!stats)  throw new IllegalStateException (
                               "Not collecting statistics for this resource");
        statUtil.init();
        statUtil.update (capacity - available);
        statCapacity.init();
        statCapacity.update (capacity);
        statSojourn.init();
        serviceList.initStat();
        waitingList.initStat();
        initStatTime = sim.time();
   }\end{hide}
\end{code}
\begin{tabb}  Reinitializes all the statistical collectors for this 
   resource.  These collectors must exist, i.e., 
   \method{setStatCollecting}{}~\texttt{(true)} must have been invoked earlier for 
   this resource.
\end{tabb}
\begin{code}

   public void init() \begin{hide} {
      serviceList.clear();
      waitingList.clear();
      available = capacity;
      if (stats) initStat();
   }\end{hide}
\end{code}
\begin{tabb}  Reinitializes this resource by clearing up its waiting list
   and service list.  The processes that were in these lists (if any)
   remain in the same states.   If statistical collection is ``on'',
   \method{initStat}{} is invoked as well.
\end{tabb}
\begin{code}

   public int getCapacity() \begin{hide} {
      return capacity;
   }\end{hide}
\end{code}
\begin{tabb}  Returns the current capacity of the resource.
\end{tabb}
\begin{htmlonly}
   \return{the capacity of the resource}
\end{htmlonly}
\begin{code}

   public void setPolicyFIFO()\begin{hide} {
      policy = FIFO;
   }\end{hide}
\end{code}
 \begin{tabb} Set the service policy to FIFO (\emph{first in, first out}): 
   the processes are placed in the
   list (and served) according to their order of arrival.
\end{tabb}
\begin{code}

   public void setPolicyLIFO()\begin{hide} {
      policy = LIFO;
   }\end{hide}
\end{code}
\begin{tabb} Set the service policy to LIFO (\emph{last in, first out}):
   the processes are placed in the
   list (and served) according to their inverse order of arrival,
   the last arrived are served first.
%   \texttt{PRIOR} (priority): the processes must give a priority number 
%   when they ask for the resource \texttt{requestWithPriority}, and they are
%   ordered in the waiting list by order of priority (those with 
%   highest priority are served first).
%   \pierre {Not yet implemented.  Resources with priorities should be 
%     implemented as a subclass of \texttt{Resource}.}
\end{tabb}
\begin{code}

   public void changeCapacity (int diff) \begin{hide} {
             if (diff > 0) {
                available += diff;
                capacity += diff;
                if (waitingList.size() > 0) startNewCust();
             }
             else {
                if (-diff > available) 
                   throw new IllegalArgumentException("Trying to diminish the capacity "
                         + "of a resource more than its current availability");
                available -= -diff;
                capacity -= -diff;
                }
                if (stats) statCapacity.update (capacity);
    }\end{hide}
\end{code}
\begin{tabb}  Modifies by \texttt{diff} units (increases if \texttt{diff > 0},
   decreases if \texttt{diff < 0}) the capacity (i.e., the number of units)
   of the resource.
   If \texttt{diff > 0} and there are processes in the waiting list whose
   request can now be satisfied, they obtain the resource.
   If \texttt{diff < 0}, there must be at least \texttt{diff} units of this
   resource available, otherwise an illegal argument exception will be thrown,
   printing an  error message (this is not a strong limitation, because one 
   can check first and release some units, if needed, before invoking 
   \texttt{changeCapacity}).
   In particular, the capacity of a resource can never become negative.
\end{tabb}
\begin{htmlonly}
   \param{diff}{number of capacity units to add to the actual capacity,
     can be negative to reduce the capacity}
   \exception{IllegalArgumentException}{if \texttt{diff} is negative and
     the capacity cannot be reduced as required}
   \exception{IllegalStateException}{if \texttt{diff} is negative and
    the capacity could not be reduced due to a lack of available units}
\end{htmlonly}
\begin{code}

   public void setCapacity (int newcap) \begin{hide} {
      if (newcap < 0)
         throw new IllegalArgumentException ("capacity cannot be negative");
      changeCapacity (newcap - capacity);
   }\end{hide}
\end{code}
\begin{tabb}  Sets the capacity to \texttt{newcap}.
   Equivalent to \method{changeCapacity}{}~\texttt{(newcap - old)} if \texttt{old} is the
   current capacity.
\end{tabb}
\begin{htmlonly}
   \param{newcap}{new capacity of the resource}
   \exception{IllegalArgumentException}{if the passed capacity is negative}
   \exception{IllegalStateException}{if \texttt{diff} is negative and
    the capacity could not be reduced due to a lack of available units}
\end{htmlonly}
\begin{code}

   public int getAvailable() \begin{hide} { 
      return available;
   }\end{hide}
\end{code}
\begin{tabb}  Returns the number of available units, i.e., the capacity
   minus the number of units busy.
\end{tabb}
\begin{htmlonly}
   \return{the number of available units}
\end{htmlonly}
\begin{code}

   public void request (int n) \begin{hide} {
        SimProcess p = sim.currentProcess();
        UserRecord record = new UserRecord (n, p, sim.time());
        if (n <= available) {
            // The process gets the resource right away.
            available -= n;
            serviceList.addLast (record);
            if (stats) {
               waitingList.statSojourn().add (0.0);
               statUtil.update (capacity - available);
            }
        }
        else {
            // Not enough units of the resource are available.
            // The process joins the queue waitingList;
            switch (policy) {
                case FIFO : waitingList.addLast (record); break;
                case LIFO : waitingList.addFirst (record); break;
                default   : throw new IllegalStateException(
                                                "policy must be FIFO or LIFO");
            }
            p.suspend();
        }
   }\end{hide}
\end{code}
\begin{tabb}  The executing process invoking this method requests for
   \texttt{n} units of this resource.  If there are enough units available
   to fill up the request immediately, the process obtains the desired
   number of units and holds them until it invokes \method{release}{}
   for this same resource.  The process is also inserted into the 
   \method{servList}{} list for this resource.
   On the other hand, if there are less than \texttt{n} units of this
   resource available, the executing process is placed into the 
   \method{waitList}{} list (the queue) for this resource and is suspended
   until it can obtain the requested number of units of the resource.
\end{tabb}
\begin{htmlonly}
   \param{n}{number of required units}
\end{htmlonly}
\iffalse  %%%%%%%%
   public void requestWithPriority (int n, int prior) {
      Throw new UnsupportedOperationException 
                ("requestWithPriority not yet implemented");
   }
\begin{tabb}  Similar to \texttt{request}, except that the resource is requested
   with a priority value \texttt{prior}.  This method must be used when the
   service policy for this resource is of type \texttt{Priority}.
   Higher priorities are ahead in the waiting queue, and processes with
   equal priorities are served according to their order of arrival.
 \pierre {This method should appear only in a subclass of \texttt{Resource}
   called, say, \texttt{ResourceWithPrior}. }
\end{tabb}
\fi  %%%%%%%%%
\begin{code}\begin{hide}

   // Called by \texttt{release}. 
   private void startNewCust() {
       UserRecord record;
       ListIterator<UserRecord> iterWait = waitingList.listIterator();
       while (iterWait.hasNext() && available > 0) {
           record = iterWait.next();
           if (record.process.getState() == SimProcess.DEAD) iterWait.remove(); 
              // the process was killed, so we remove it from the waiting list.
              // or maybe we stop the program by throwing IllegalStateException
              //"Resource.startNewCust: process not alive");

               // The thread for this process is still alive.
           else if (record.numUnits <= available) {
               // This request can now be satisfied.
               serviceList.addLast (record);
               record.process.resume();
               available -= record.numUnits;
               iterWait.remove();
           }
       }
    }\end{hide}

   public void release (int n) \begin{hide} {
        SimProcess p = sim.currentProcess();
        int temp = 0;
        UserRecord record;
        ListIterator<UserRecord> iterServ = serviceList.listIterator();
        while (temp<n && iterServ.hasNext()) {
            record = iterServ.next();
            if (p == record.process) {
                temp = temp + record.numUnits;
                if (temp <= n) {
                    iterServ.remove();
                    if (stats) statSojourn.add
                                   (sim.time() - record.requestTime);
                }
                else {
                    record.numUnits = temp - n;
                    temp = n;
                }
            }
        }
        if (temp < n)  throw new IllegalArgumentException ("trying to release "
                +"more units of a Resource than the process currently holds");
        available += temp;
        if (waitingList.size() > 0)  startNewCust();
        if (stats) statUtil.update (capacity - available);
    }\end{hide}
\end{code}
\begin{tabb}  The executing process that invokes this method releases 
  \texttt{n} units of the resource.  If this process is holding exactly
  \texttt{n} units, it is removed from the service list of this resource
  and its \class{UserRecord} object disappears.
  If this process is holding less than \texttt{n} units, 
  the program throws an illegal argument exception.
  If there are other processes waiting for this resource whose requests
  can now be satisfied, they obtain the resource.
\end{tabb}
\begin{htmlonly}
   \param{n}{number of released units}
   \exception{IllegalArgumentException}{if the process did not request \texttt{n}
      units before releasing them}
\end{htmlonly}
\begin{code}

   public LinkedListStat waitList() \begin{hide} { 
      return waitingList;
   }\end{hide}
\end{code}
\begin{tabb}  Returns the list that contains the
  \class{UserRecord} objects
  for the processes in the waiting list for this resource.
\end{tabb}
\begin{htmlonly}
   \return{the list of process user records waiting for the resource}
\end{htmlonly}
\begin{code}

   public LinkedListStat servList() \begin{hide} { 
      return serviceList;
   }\end{hide}
\end{code}
\begin{tabb}  Returns the list that contains the 
  \class{UserRecord} objects
  for the processes in the service list for this resource.
\end{tabb}
\begin{htmlonly}
   \return{the list of process user records using this resource}
\end{htmlonly}
\begin{code}

   public Accumulate statOnCapacity() \begin{hide} {
      return statCapacity;
   }\end{hide}
\end{code}
\begin{tabb}  Returns the statistical collector that measures the evolution of
  the capacity of the resource as a function of time.
  This collector exists only if \method{setStatCollecting}{}~\texttt{(true)} has been invoked
  previously.  
\end{tabb}
\begin{htmlonly}
   \return{the probe for resource capacity}
\end{htmlonly}
\begin{code}

   public Accumulate statOnUtil() \begin{hide} {
      return statUtil;
   }\end{hide}
\end{code}
\begin{tabb}  Returns the statistical collector for the utilization
  of the resource (number of units busy) as a function of time.
  This collector exists only if \method{setStatCollecting}{}~\texttt{(true)}
  has been invoked previously.  
  The {\em utilization rate\/} of a resource can be obtained as the
  {\em time average\/} computed by this collector, divided by the
  capacity of the resource.
  The collector returned by \method{servList()}{}\texttt{.}%
\externalmethod{umontreal.iro.lecuyer.simevents}{LinkedListStat}{statSize()}{} 
  tracks the number of \class{UserRecord}
  in the service list;
  it differs from this collector because a process may hold more than one
  unit of the resource by given \class{UserRecord}.
\end{tabb}
\begin{htmlonly}
   \return{the probe for resource utilization}
\end{htmlonly}
\begin{code}

   public Tally statOnSojourn() \begin{hide} {
      return statSojourn;
   }\end{hide}
\end{code}
\begin{tabb}  Returns the statistical collector for the sojourn times of
  the \class{UserRecord} for this resource.
  This collector exists only if \method{setStatCollecting}{}~\texttt{(true)} has been invoked
  previously.  
  It gets a new observation each time a process releases all the units
  of this resource that it had requested by a single \method{request}{}
  call.
\end{tabb}
\begin{htmlonly}
   \return{the probe for the sojourn times}
\end{htmlonly}
\begin{code}

   public String getName()\begin{hide} {
      return name;
   }\end{hide}
\end{code}
\begin{tabb}   Returns the name (or identifier) associated to this
  resource.  If it was not given upon resource construction, this returns
   \texttt{null}.
\end{tabb}
\begin{htmlonly}
   \return{the name associated to this resource, or \texttt{null} if it was not given}
\end{htmlonly}
\begin{code}

   public String report() \begin{hide} {

    if (statUtil == null) throw new IllegalStateException ("Asking a report for a resource "
                          +"for which setStatCollecting (true) has not been called");
  
    Accumulate sizeWait = waitingList.statSize();
    Tally sojWait = waitingList.statSojourn();
    Tally sojServ = serviceList.statSojourn();
   
    PrintfFormat str = new PrintfFormat(); 

    str.append ("REPORT ON RESOURCE : ").append (name).append (PrintfFormat.NEWLINE);
    str.append ("   From time : ").append (7, 2, 2, initStatTime);
    str.append ("   to time : ");
    str.append (10,2, 2, sim.time());
    str.append (PrintfFormat.NEWLINE + "                    min        max     average  ");
    str.append ("standard dev.  nb. obs.");

    str.append (PrintfFormat.NEWLINE + "   Capacity    ");
    str.append (8, (int)(statCapacity.min()+0.5));
    str.append (11, (int)(statCapacity.max()+0.5));
    str.append (12, 3, 2, statCapacity.average());
 
    str.append (PrintfFormat.NEWLINE + "   Utilization ");
    str.append (8, (int)(statUtil.min()+0.5));
    str.append (11, (int)(statUtil.max()+0.5));
    str.append (12, 3, 2, statUtil.average());
 
    str.append (PrintfFormat.NEWLINE + "   Queue Size  "); 
    str.append (8, (int)(sizeWait.min()+0.5));
    str.append (11, (int)(sizeWait.max()+0.5));
    str.append (12, 3, 2, sizeWait.average());

    str.append (PrintfFormat.NEWLINE + "   Wait    ");
    str.append (12, 3, 2, sojWait.min()).append (' ');
    str.append (10, 3, 2, sojWait.max()).append (' ');
    str.append (11, 3, 2, sojWait.average()).append (' ');
    str.append (10, 3, 2, sojWait.standardDeviation());
    str.append (10, sojWait.numberObs());
   
    str.append (PrintfFormat.NEWLINE + "   Service ");
    str.append (12, 3, 2, sojServ.min()).append (' ');  
    str.append (10, 3, 2, sojServ.max()).append (' ');
    str.append (11, 3, 2, sojServ.average()).append (' ');
    str.append (10, 3, 2, sojServ.standardDeviation());
    str.append (10, sojServ.numberObs());
    
    str.append (PrintfFormat.NEWLINE + "   Sojourn ");
    str.append (12, 3, 2, statSojourn.min()).append (' ');
    str.append (10, 3, 2, statSojourn.max()).append (' ');
    str.append (11, 3, 2, statSojourn.average()).append (' ');
    str.append (10, 3, 2, statSojourn.standardDeviation());
    str.append (10, statSojourn.numberObs()).append (PrintfFormat.NEWLINE);
    
    return str.toString();
   }
}\end{hide}
\end{code}
\begin{tabb}  Returns a string containing a complete statistical report on this 
  resource.  The method \method{setStatCollecting}{}~\texttt{(true)} must have been invoked 
  previously, otherwise no statistics have been collected.
  The report contains statistics on the waiting times, service
  times, and waiting times for this resource, on the capacity,
  number of units busy, and size of the queue as a function of time,
  and on the utilization rate.
\end{tabb}
\begin{htmlonly}
   \return{a statistical report for this resource, represented as a string}
\end{htmlonly}
